package edu.arizona.sista.learn.model.displaying;

import java.util.ArrayList;
import java.util.List;

import edu.arizona.sista.learn.model.Interval;
import edu.arizona.sista.learn.model.holding.Object;
import edu.arizona.sista.learn.model.holding.Person;
import edu.arizona.sista.learn.model.holding.HoldingAnObject;
import edu.arizona.sista.learn.model.holding.Scene;
import edu.arizona.sista.learn.util.Computable;

/**
 * DisplayingSomething is the collection of actions in which instances of objects are intentionally made
 * to be visually accessible by people.
 */
public class DisplayingSomething extends Event{
	public Person _doer;
	public Object _object;
	public List<Event> _subevents;

	public DisplayingSomething(Interval time) {
		super(time);
	}

	public DisplayingSomething(Person p, Object o, Interval t) {
		super(t);
		_doer = p;
		_object = o;
		_subevents = new ArrayList<Event>();
	}
	
	public void addSubEvent(Event e){
		_subevents.add(e);
	}

	/**
	 * Static method to infer displayed things from a scene
	 * @param scene
	 * @param window
	 */
	public static void getDisplayedThings(Scene scene, int window) {
		//the rule is:
		//if somebody is holding an object (event 1)
		//and somebody else is watching the object long enough (event 2)
		//and the object is between both during the second event
		//then both events can be generalized to a DisplayingEvent
		
		List<HoldingAnObject> listHAO = scene.getHoldingAnObjectEvents();
		List<WatchingSomething> listWS = scene.getWatchingSomethingEvents();
		
		for (HoldingAnObject hao : listHAO){
			Interval t1 = hao._time;
			for (WatchingSomething ws : listWS){
				Interval t2 = ws._time;
				
				//Does the second event last long enough?
				if (t2.duration() < window) continue;
				
				//Same object?
				if (!hao._object.equals(ws._object)) continue;
				Object o = hao._object;
				
				//So the first event temporally subsumes the second?
				if (!t1.temporallySubsumes(t2, window)) continue;
				
				//Is the object between both people during t2?
				Person p1 = scene.getActorFromBodyPart(hao._hand);
				Person p2 = ws._doer;
				if (!Computable.between(p1, p2, o, t2)) continue;

				//Oh oh oh, we have got every predicate, let us create a DisplayingSomething event!
				DisplayingSomething ds = new DisplayingSomething(p1, o, t1);
				ds.addSubEvent(hao);
				ds.addSubEvent(ws);
				scene.addEvent(ds);
			}
		}
	}
	
	@Override
	public String toString() {
		String s1 = "isa(" + getVariableName() + ", DisplayingSomething)\n";
		String s2 = "perfomedBy(" + getVariableName() + ", " + _doer.getVariableName() + ")\n";
		String s3 = "objectActedOn(" + getVariableName() + ", " + _object.getVariableName() + ")\n";
		String t = "t_"  + _time.start() + "-" + _time.end();
		String s4 = "temporalExtent(" + getVariableName() + ", " + t + ")\n";
		StringBuffer sb = new StringBuffer();
		for (Event e: _subevents)
			sb.append("subEvents(" + getVariableName() + ", " + e.getVariableName() + ")\n");
		return s1 + s2 + s3 + s4 + sb;
	}

	public List<Person> getRecipientsOfInfo() {
		List<Person> output = new ArrayList<Person>();
		for (Event e : _subevents)
			if (e instanceof WatchingSomething && ((WatchingSomething) e)._object.equals(_object)) output.add(((WatchingSomething) e)._doer);
		return output;
	}
}
